home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 February: Technology Seed / Mac Tech Seed Feb '97.toast / OpenDoc 1.2b2c1 / TestParts / DragText / DragTxPv.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-01-01  |  34.0 KB  |  1,359 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        DragTxPv.cpp
  3.  
  4.     Contains:    Static functions used by DragText implementation.
  5.  
  6.     Owned by:    Craig Carper
  7.  
  8.     Copyright:    © 1993 - 1995 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.         <17>     9/13/95    DM        1277216 GM:API return no ODPoints nor
  13.                                     ODPolygons
  14.         <16>      9/4/95    TJ        Added Includes to Compile with out
  15.                                     PC-Headers.
  16.         <15>     6/28/95    CC        1262618: Added GetFSSpecFromHFSProperty(),
  17.                                     ReadTextFile(), InsertFromTextFile(),
  18.                                     SURemoveValue(), and IsFrontProcess().
  19.         <14>     6/26/95    JBS        &DMc&TÇ 1242642 BB: Refcounting Fixes.
  20.         <13>      6/6/95    CC        1256250: DrawLinkBorder:  Clip out
  21.                                     surrounding frame when drawing link
  22.                                     borders.
  23.         <12>      6/5/95    TJ        Moved AltPoint up above where ODTypes is
  24.                                     included.
  25.         <11>     5/31/95    TJ        Included GXMath.h insted of math routines.h
  26.         <10>     5/26/95    RR        #1251403: Multithreading naming support
  27.          <9>     5/25/95    jpa        Use new control/dialog mgr consts [1253324]
  28.          <8>     2/24/95    jpa        Use ODNewRgn. [1220810]
  29.          <7>     2/24/95    CC        Disabled link border debugging strings.
  30.          <6>     1/12/95    jpa        Don't use obsolete Toolbox names [1211211]
  31.          <5>      1/9/95    NP        1194880: SemtIntf name changes.
  32.          <4>    12/20/94    VL        1195012: Make Storage calls be
  33.                                     marshallable.
  34.          <3>    11/28/94    CC        Checkin of changes to revision 2 noted
  35.                                     below.
  36.          <2+1>    11/14/94    CC        Added DrawLinkBorder, LineHeightAtOffset,
  37.                                      TELastLineOffset, DragTextDialogFilter.
  38.                                      TEGetLine returns nLines-1 if last offset
  39.                                     (or greater) is input.
  40.          <2>     9/30/94    CC        1189416 - Utility functions for DragText
  41.                                     'ternalization.
  42.          <1>     9/29/94    RA        first checked in
  43.          <1>      9/8/94    CC        first checked in
  44.     
  45.     In Progress:
  46.         
  47. */
  48.  
  49. #ifndef _ALTPOINT_
  50. #include "AltPoint.h"            // Use C++ savvy ODPoint and ODRect
  51. #endif
  52.  
  53. #include <DragText.xh>
  54. #include "DragTxPv.h"
  55.  
  56. #ifndef _DRAGDEF_
  57. #include <DragDef.h>
  58. #endif
  59.  
  60. #ifndef _DRAGCONS_
  61. #include <DragCons.h>
  62. #endif
  63.  
  64. #ifndef _PLFMDEF_
  65. #include "PlfmDef.h"
  66. #endif
  67.  
  68. #ifndef __QUICKDRAW__
  69. #include <Quickdraw.h>
  70. #endif
  71.  
  72. #ifndef __STRING__
  73. #include <String.h>
  74. #endif
  75.  
  76. #ifndef __OSUTILS__
  77. #include <OSUtils.h>    // SysBeep, GetDateTime, etc.
  78. #endif
  79.  
  80. #ifndef __OSEVENTS__
  81. #include <OSEvents.h>
  82. #endif
  83.  
  84. #ifndef __TOOLUTILS__
  85. #include <ToolUtils.h>    // HiWord etc.
  86. #endif
  87.  
  88. #ifndef __SCRAP__
  89. #include <Scrap.h>
  90. #endif
  91.  
  92. #ifndef __LOWMEM__
  93. #include <LowMem.h>
  94. #endif
  95.  
  96. #ifndef __FILES__
  97. #include <Files.h>
  98. #endif
  99.  
  100. #ifdef __SC__
  101.  
  102. #ifndef __LANGUAGE__
  103. #include <Language.h>
  104. #endif
  105.  
  106. #endif // __SC__
  107.  
  108. #ifndef SOM_Module_OpenDoc_StdProps_defined
  109. #include <StdProps.xh>
  110. #endif
  111.  
  112. #ifndef SOM_Module_OpenDoc_StdTypes_defined
  113. #include <StdTypes.xh>
  114. #endif
  115.  
  116. #ifndef SOM_ODStorageUnit_xh
  117. #include <StorageU.xh>
  118. #endif
  119.  
  120. #ifndef SOM_ODDraft_xh
  121. #include <Draft.xh>
  122. #endif
  123.  
  124. #ifndef SOM_ODDocument_xh
  125. #include <Document.xh>
  126. #endif
  127.  
  128. #ifndef SOM_ODContainer_xh
  129. #include <ODCtr.xh>
  130. #endif
  131.  
  132. #ifndef _ODDEBUG_
  133. #include "ODDebug.h"
  134. #endif
  135.  
  136. #ifndef SOM_ODSession_xh
  137. #include <ODSessn.xh>
  138. #endif
  139.  
  140. #ifndef SOM_ODWindowState_xh
  141. #include <WinStat.xh>
  142. #endif
  143.  
  144. #ifndef SOM_ODArbitrator_xh
  145. #include <Arbitrat.xh>
  146. #endif
  147.  
  148. #ifndef SOM_ODDispatcher_xh
  149. #include <Disptch.xh>
  150. #endif
  151.  
  152. #ifndef SOM_ODFrame_xh
  153. #include <Frame.xh>
  154. #endif
  155.  
  156. #ifndef SOM_ODFacet_xh
  157. #include <Facet.xh>
  158. #endif
  159.  
  160. #ifndef SOM_ODFrameFacetIterator_xh
  161. #include <FrFaItr.xh>
  162. #endif
  163.  
  164. #ifndef SOM_ODCanvas_xh
  165. #include <Canvas.xh>
  166. #endif
  167.  
  168. #ifndef SOM_ODDraft_xh
  169. #include <Draft.xh>
  170. #endif
  171.  
  172. #ifndef SOM_ODShape_xh
  173. #include <Shape.xh>
  174. #endif
  175.  
  176. #ifndef SOM_ODTransform_xh
  177. #include <Trnsform.xh>
  178. #endif
  179.  
  180. #ifndef SOM_ODWindow_xh
  181. #include <Window.xh>
  182. #endif
  183.  
  184. #ifndef SOM_ODMenuBar_xh
  185. #include <MenuBar.xh>
  186. #endif
  187.  
  188. #ifndef _EXCEPT_
  189. #include "Except.h"
  190. #endif
  191.  
  192. #ifndef SOM_ODDragAndDrop_xh
  193. #include <DragDrp.xh>
  194. #endif
  195.  
  196. #ifndef SOM_ODDragItemIterator_xh
  197. #include <DgItmIt.xh>
  198. #endif
  199.  
  200. #ifndef SOM_ODStorageUnitView_xh
  201. #include <SUView.xh>
  202. #endif
  203.  
  204. #ifndef SOM_Module_OpenDoc_Commands_defined
  205. #include <CmdDefs.xh>
  206. #endif
  207.  
  208. #ifndef SOM_ODUndo_xh
  209. #include <Undo.xh>
  210. #endif
  211.  
  212. #ifndef SOM_ODFocusSet_xh
  213. #include <FocusSet.xh>
  214. #endif
  215.  
  216. #ifndef SOM_Module_OpenDoc_Foci_defined
  217. #include <Foci.xh>
  218. #endif
  219.  
  220. #ifndef _ODUTILS_
  221. #include <ODUtils.h>
  222. #endif
  223.  
  224. #ifndef _ORDCOLL_
  225. #include "OrdColl.h"
  226. #endif
  227.  
  228. #ifndef SOM_ODClipboard_xh
  229. #include <Clipbd.xh>
  230. #endif
  231.  
  232. #ifndef SOM_ODLink_xh
  233. #include <Link.xh>
  234. #endif
  235.  
  236. #ifndef SOM_ODLinkSource_xh
  237. #include <LinkSrc.xh>
  238. #endif
  239.  
  240. #ifndef SOM_ODLinkSpec_xh
  241. #include <LinkSpec.xh>
  242. #endif
  243.  
  244. #ifndef _ODMEMORY_
  245. #include "ODMemory.h"
  246. #endif
  247.  
  248. #ifndef _ISOSTR_
  249. #include "ISOStr.h"
  250. #endif
  251.  
  252. #ifndef SOM_ODNameSpaceManager_xh
  253. #include <NmSpcMg.xh>
  254. #endif
  255.  
  256. #ifndef SOM_ODValueNameSpace_xh
  257. #include <ValueNS.xh>
  258. #endif
  259.  
  260. #ifndef SOM_Module_OpenDoc_StdDefs_defined
  261. #include <StdDefs.xh>    //jpa
  262. #endif
  263.  
  264. #ifndef _FOCUSLIB_
  265. #include "FocusLib.h"    // for drawing/printing
  266. #endif
  267.  
  268. #ifndef __STDTYPIO__
  269. #include "StdTypIO.h"    // for labs
  270. #endif
  271.  
  272. #ifndef __GXMATH__
  273. #include <GXMath.h>
  274. #endif
  275.  
  276. #ifndef __QDOFFSCREEN__
  277. #include "QDOffscreen.h"    // for GWorldPtr, StScrpHandle
  278. #endif
  279.  
  280. #ifndef __STDLIB__
  281. #include "stdlib.h"    // for labs
  282. #endif
  283.  
  284. #ifndef _PASCLSTR_
  285. #include "PasclStr.h"
  286. #endif
  287.  
  288. #ifndef _STORUTIL_
  289. #include <StorUtil.h>
  290. #endif
  291.  
  292. #ifndef _TEMPOBJ_
  293. #include "TempObj.h"
  294. #endif
  295.  
  296. #pragma segment DragTextPrivate
  297.  
  298. #ifdef ODDebug
  299. #define DEBUG_DRAGTEXT 1
  300. #else
  301. #undef DEBUG_DRAGTEXT
  302. #endif
  303.  
  304. #undef DEBUG_LINK_BORDERS
  305.  
  306. //==============================================================================
  307. // Forward Declarations
  308. //==============================================================================
  309.  
  310. ODSShort LineHeightAtOffset(ODSShort offset, TEHandle theTEHandle);
  311. short TENextLineOffset(short line, TEHandle theTE);
  312.  
  313. //-------------------------------------------------------------------------
  314. // IncludedInRange
  315. //-------------------------------------------------------------------------
  316.  
  317. extern ODBoolean IncludedInRange(ODSShort start, ODSShort end, ODSShort startRange, ODSShort endRange)
  318. {
  319.     return (startRange <= start) && (endRange >= end);
  320. }
  321.  
  322. //-------------------------------------------------------------------------
  323. // OneDragItem
  324. //-------------------------------------------------------------------------
  325.  
  326. extern ODBoolean OneDragItem(Environment *ev, ODDragItemIterator* dropInfo)
  327. {
  328.     ODBoolean result = kODFalse;
  329.     
  330.     dropInfo->First(ev);
  331.     result = dropInfo->IsNotComplete(ev);
  332.     if (result)
  333.     {
  334.         dropInfo->Next(ev);
  335.         result = !dropInfo->IsNotComplete(ev);
  336.     }
  337.     
  338.     return result;
  339. }
  340.  
  341.  
  342. //-------------------------------------------------------------------------
  343. // IsKind
  344. //-------------------------------------------------------------------------
  345.  
  346. extern ODBoolean IsKind(ODType type, ODISOStr kind)
  347. {
  348.     return !ODISOStrCompare( (ODISOStr) type, kind );
  349. }
  350.  
  351. //-------------------------------------------------------------------------
  352. // PeekIntoValue
  353. //-------------------------------------------------------------------------
  354.  
  355. extern char PeekIntoValue(Environment *ev, ODStorageUnit* su, ODValueType kind, ODSLong offset)
  356. // Returns the character at the specified offset; negative offsets are relative to the
  357. // end, with -1 denoting the last character.
  358. {
  359.     ODStorageUnit* suRelease = (ODStorageUnit*) kODNULL;
  360.     char ch = ' ';
  361.     TRY
  362.         if ( IsKind(kind, kODKindTestDrag) )
  363.         {
  364.             ODStorageUnitRef aSURef;
  365.             su->Focus(ev, kODPropContents, kODPosUndefined, (ODValueType) kODKindTestDrag, 0, kODPosUndefined);
  366.             StorageUnitGetValue(su, ev, sizeof(ODStorageUnitRef),&aSURef);
  367.             suRelease = su->GetDraft(ev)->AcquireStorageUnit(ev, su->GetIDFromStorageUnitRef(ev, aSURef));
  368.             su = suRelease;
  369.             su->Focus(ev, kDragTextPropText, kODPosUndefined, (ODValueType) kODAppleTEXT, 0, kODPosUndefined);
  370.         }
  371.         else
  372.         {
  373.             su->Focus(ev, kODPropContents, kODPosUndefined, kind, 0, kODPosUndefined);
  374.         }
  375.  
  376.         ODULong size = su->GetSize(ev);
  377.         if ( offset < 0 )
  378.         {
  379.             // Rather than mix signed and unsigned values in expressions,
  380.             // convert to an unsigned offset relative to the end.
  381.             ODULong endOffset = labs(offset);
  382.             if ( (size >= endOffset) )
  383.             {
  384.                 su->SetOffset(ev, size - endOffset);
  385.                 StorageUnitGetValue(su, ev, 1, (ODValue) &ch);
  386.             }
  387.         }
  388.         else
  389.         {
  390.             if ( offset < size )
  391.             {
  392.                 su->SetOffset(ev, offset);
  393.                 StorageUnitGetValue(su, ev, 1, (ODValue) &ch);
  394.             }
  395.         }
  396.         su->SetOffset(ev, 0);
  397.     CATCH_ALL
  398.     ENDTRY
  399.     
  400.     ODReleaseObject(ev,suRelease);
  401.  
  402.     return ch;
  403. }
  404.  
  405. //-------------------------------------------------------------------------
  406. // TempSelect
  407. //-------------------------------------------------------------------------
  408.  
  409. extern void TempSelect(ODSShort start, ODSShort end, TEHandle theTE, ODBoolean isActive)
  410. {
  411.     // Temporarily change the selection to the argument range.
  412.     // The hilighting is not changed.
  413.     
  414.     RgnHandle saveClip;
  415.  
  416.     if (isActive)
  417.     {
  418.         saveClip = ODNewRgn();
  419.         GetClip(saveClip);
  420.  
  421.         RgnHandle clipRgn;
  422.         clipRgn = ODNewRgn();
  423.         SetClip(clipRgn);
  424.         DisposeRgn(clipRgn);
  425.     }
  426.  
  427.     TESetSelect(start, end, theTE); 
  428.  
  429.     if (isActive)
  430.     {
  431.         SetClip(saveClip);
  432.         DisposeRgn(saveClip);
  433.     }
  434. }
  435.  
  436.  
  437. //-------------------------------------------------------------------------
  438. // RangesOverlap
  439. //-------------------------------------------------------------------------
  440.  
  441. extern ODBoolean RangesOverlap(ODSShort start1, ODSShort end1,ODSShort start2,ODSShort end2)
  442. // Returns kODTrue if the two argument text offset ranges overlap
  443. {
  444.     if (start1 >= end2)
  445.         return kODFalse;
  446.     else if (start2 >= end1)
  447.         return kODFalse;
  448.     else if (start1 < start2) {
  449.         if (end1 <= start2)
  450.             return kODFalse;
  451.         else
  452.             return kODTrue;
  453.         }
  454.     else
  455.         return kODTrue;
  456. }
  457.  
  458. //-------------------------------------------------------------------------
  459. // PasteThisKind
  460. //-------------------------------------------------------------------------
  461.  
  462. extern ODBoolean PasteThisKind(Environment *ev, ODStorageUnit* su, ODType aKind, ODType specifiedKind)
  463. // Returns true if aKind exists in the contents property of the argument storage unit
  464. // and specifiedKind is either nil (don't care) or the same as aKind.
  465. {
  466.     return ( su->Exists(ev, kODPropContents, aKind, kODPosAll)
  467.         && ((specifiedKind == (ODType) kODNULL) || (IsKind(aKind, specifiedKind))) );
  468. }
  469.  
  470. //-------------------------------------------------------------------------
  471. // LinkSpecInSU
  472. //-------------------------------------------------------------------------
  473.  
  474. extern ODBoolean LinkSpecInSU(Environment *ev, ODStorageUnit* su)
  475. {
  476.     ODBoolean result = kODFalse;
  477.  
  478.     TRY
  479.         result = su->Exists(ev, kODPropLinkSpec, (ODValueType) kODLinkSpec, 0);
  480.     CATCH_ALL
  481.     ENDTRY
  482.  
  483.     return result;
  484. }
  485.  
  486. //-------------------------------------------------------------------------
  487. // ValueOnClipboard
  488. //-------------------------------------------------------------------------
  489.  
  490. extern ODBoolean ValueOnClipboard(Environment *ev, ODValueType type, ODSession* session)
  491. {
  492.     ODBoolean        result = kODFalse;
  493.     ODClipboard*    clipboard = session->GetClipboard(ev);
  494.  
  495.     TRY
  496.         ODStorageUnit* su = clipboard->GetContentStorageUnit(ev);
  497.         result = su->Exists(ev, kODPropContents, type, 0);
  498.     CATCH_ALL
  499.     ENDTRY
  500.  
  501.     return result;
  502. }
  503.  
  504. //-------------------------------------------------------------------------
  505. // GetAggregateTranslation
  506. //-------------------------------------------------------------------------
  507.  
  508. extern ODPoint GetAggregateTranslation(Environment *ev, ODFacet* facet)
  509. {
  510.     ODPoint xForm(0,0);
  511.     TempODTransform facetXform = facet->AcquireWindowContentTransform(ev, kODNULL);
  512.     facetXform->TransformPoint(ev, &xForm);
  513.     return xForm;
  514. }
  515.  
  516. //-------------------------------------------------------------------------
  517. // CheckMarkMenu
  518. //-------------------------------------------------------------------------
  519.  
  520. extern void CheckMarkMenu(MenuHandle menu, Str255 checkItem, ODBoolean checkIt)
  521. {
  522.     ODSShort      numMenuItems = CountMItems( menu );
  523.     Str255      menuItemString;
  524.     
  525.     for (ODSShort menuItemNum = 1; menuItemNum <= numMenuItems; menuItemNum++)
  526.     {
  527.         GetMenuItemText( menu, menuItemNum, menuItemString );
  528.         
  529.         if ( IUEqualString(checkItem, menuItemString) == 0 )
  530.         {
  531.             if ( checkIt )
  532.                 CheckItem( menu, menuItemNum, kODTrue );
  533.             else
  534.                 CheckItem( menu, menuItemNum, kODFalse );
  535.         }
  536.     }
  537. }
  538.  
  539. //-------------------------------------------------------------------------
  540. // DrawOffscreen
  541. //-------------------------------------------------------------------------
  542.  
  543. extern WindowOffscreen *DrawOffscreen(WindowPtr theWindow)
  544. {    
  545.     WindowOffscreen        *theOffscreen;
  546.     GWorldPtr            theWorld;
  547.     Rect                globalRect;
  548.  
  549.     if ((theOffscreen = (WindowOffscreen *) ODNewPtr(sizeof(WindowOffscreen), kDefaultHeapID)) == 0L)
  550.         return(0L);
  551.  
  552.     SetPort(theWindow);
  553.     GetGWorld(&theOffscreen->windowPort, &theOffscreen->windowDevice);
  554.  
  555.     globalRect = theWindow->portRect;
  556.     LocalToGlobal((Point *) &globalRect.top);
  557.     LocalToGlobal((Point *) &globalRect.bottom);
  558.     
  559.     if (NewGWorld(&theWorld, 0, &globalRect, 0L, 0L, 0) == noErr)
  560.     {
  561.         SetGWorld(theWorld, 0L);
  562.         if (!LockPixels(theWorld->portPixMap))
  563.         {
  564.             DisposeGWorld(theWorld);
  565.             ODDisposePtr((Ptr)theOffscreen);
  566.             return(0L);
  567.         }
  568.  
  569.         CopyBits(&theWindow->portBits,
  570.                  &((GrafPtr) theWorld)->portBits,
  571.                  &theWindow->portRect,
  572.                  &theWorld->portRect,
  573.                  srcCopy, 0L);
  574.  
  575.         theOffscreen->offscreenWorld = theWorld;
  576.         SetPort(theWindow);
  577.         return(theOffscreen);
  578.     } 
  579.     else 
  580.     {
  581.         ODDisposePtr((Ptr)theOffscreen);
  582.         return(0L);
  583.     }
  584. }
  585.  
  586. //-------------------------------------------------------------------------
  587. // DrawOnscreen
  588. //-------------------------------------------------------------------------
  589.  
  590. extern void DrawOnscreen(WindowOffscreen *theOffscreen)
  591. {
  592.     SetGWorld(theOffscreen->windowPort, theOffscreen->windowDevice);
  593.     CopyBits(&((GrafPtr) theOffscreen->offscreenWorld)->portBits,
  594.              &((GrafPtr) theOffscreen->windowPort)->portBits,
  595.              &theOffscreen->offscreenWorld->portRect,
  596.              &theOffscreen->windowPort->portRect,
  597.              srcCopy, 0L);
  598.     UnlockPixels(theOffscreen->offscreenWorld->portPixMap);
  599.     DisposeGWorld(theOffscreen->offscreenWorld);
  600.     ODDisposePtr((Ptr) theOffscreen);
  601. }
  602.  
  603. //-------------------------------------------------------------------------
  604. // DrawCaret
  605. //-------------------------------------------------------------------------
  606. /*
  607.  *    DrawCaret draws a caret in a TextEdit field at the given offset. DrawCaret
  608.  *    expects the port to be set to the port that the TextEdit field is in.
  609.  *    A clipping region may be optionally given to clip the drawing to. DrawCaret
  610.  *    inverts the image of the caret onto the screen.
  611.  */
  612.  
  613. extern void DrawCaret(short offset, TEHandle theTE, RgnHandle clipRgn)
  614. {    
  615.     Point        theLoc;
  616.     short        theLine, lineHeight;
  617.     RgnHandle    oldClip;
  618.  
  619.     /*
  620.      *    Get the coordinates and the line of the offset to draw the caret.
  621.      */
  622.  
  623.     theLoc  = TEGetPoint(offset, theTE);
  624.     theLine = TEGetLine(offset, theTE);
  625.  
  626.     /*
  627.      *    For some reason, TextEdit dosen't return the proper coordinates
  628.      *    of the last offset in the field if the last character in the record
  629.      *    is a carriage return. TEGetPoint returns a point that is one line
  630.      *    higher than expected. The following code fixes this problem.
  631.      */
  632.  
  633.     if ((offset == (**theTE).teLength) &&
  634.             (*((char **)(**theTE).hText))[(**theTE).teLength - 1] == 0x0D) {
  635.         theLoc.v += (short)(TEGetHeight(theLine, theLine, theTE));
  636.     }
  637.  
  638.     /*
  639.      *    Always invert the caret when drawing.
  640.      */
  641.  
  642.     PenMode(patXor);
  643.  
  644.     /*
  645.      *    Get the height of the line that the offset points to.
  646.      */
  647.  
  648.     lineHeight = (short)(TEGetHeight(theLine, theLine, theTE));
  649.  
  650.     /*
  651.      *    If we are given a clip region, use it to draw the caret.
  652.      */
  653.  
  654.     if (clipRgn) {
  655.         oldClip = ODNewRgn();
  656.         GetClip(oldClip);
  657.         SetClip(clipRgn);
  658.     }
  659.  
  660.     /*
  661.      *    Draw the appropriate caret image.
  662.      */
  663.  
  664.     MoveTo(theLoc.h - 1, theLoc.v - 1);
  665.     Line(0, 1 - lineHeight);
  666.  
  667.     /*
  668.      *    Restore the clipping region, if necessary.
  669.      */
  670.  
  671.     if (clipRgn) {
  672.         SetClip(oldClip);
  673.         DisposeRgn(oldClip);
  674.     }
  675.  
  676.     PenNormal();
  677. }
  678.  
  679. //-------------------------------------------------------------------------
  680. // GetCharAtOffset
  681. //-------------------------------------------------------------------------
  682.  
  683. extern char GetCharAtOffset(short offset, TEHandle theTE)
  684. {
  685.     if (offset < 0)
  686.         return(0x0D);
  687.  
  688.     return(((char *) *((**theTE).hText))[offset]);
  689. }
  690.  
  691. //-------------------------------------------------------------------------
  692. // WhiteSpace
  693. //-------------------------------------------------------------------------
  694.  
  695. extern Boolean WhiteSpace(char theChar)
  696. {
  697.     return((theChar == ' ') || (theChar == 0x0D));
  698. }
  699.  
  700. //-------------------------------------------------------------------------
  701. // WhiteSpaceAtOffset
  702. //-------------------------------------------------------------------------
  703.  
  704. extern Boolean WhiteSpaceAtOffset(short offset, TEHandle theTE)
  705. {    
  706.     char        theChar;
  707.  
  708.     if (offset < 0)
  709.         return(true);
  710.  
  711.     theChar = ((char *) *((**theTE).hText))[offset];
  712.     return((theChar == ' ') || (theChar == 0x0D));
  713. }
  714.  
  715.  
  716. //-------------------------------------------------------------------------
  717. // InsertTextAtOffset
  718. //-------------------------------------------------------------------------
  719.  
  720. extern void InsertTextAtOffset(short offset, char *theBuf, long size, StScrpHandle theStyl, TEHandle theTE)
  721. {
  722.     if (size == 0)
  723.         return;
  724.  
  725.     //
  726.     //    If inserting at the end of a word and the selection does not begin with
  727.     //    a space, insert a space before the insertion.
  728.     //
  729.  
  730.     if (!WhiteSpaceAtOffset(offset - 1, theTE) &&
  731.          WhiteSpaceAtOffset(offset, theTE) &&
  732.         !WhiteSpace(theBuf[0])) {
  733.  
  734.         TESetSelect(offset, offset, theTE);
  735.         TEKey(' ', theTE);
  736.         offset++;
  737.     }
  738.  
  739.     //
  740.     //    If inserting at the beginning of a word and the selection does not end
  741.     //    with a space, insert a space after the insertion.
  742.     //
  743.  
  744.     if ( WhiteSpaceAtOffset(offset - 1, theTE) &&
  745.         !WhiteSpaceAtOffset(offset, theTE) &&
  746.         !WhiteSpace(theBuf[size - 1])) {
  747.  
  748.         TESetSelect(offset, offset, theTE);
  749.         TEKey(' ', theTE);
  750.     }
  751.  
  752.     TESetSelect(offset, offset, theTE);
  753.     TEStyleInsert(theBuf, size, theStyl, theTE);
  754.     TESetSelect(offset, offset + size, theTE);
  755. }
  756.  
  757. //-------------------------------------------------------------------------
  758. // TEIsFrontOfLine
  759. //-------------------------------------------------------------------------
  760. /*
  761.  *    TEIsFrontOfLine, given an offset and a TextEdit handle, returns true if
  762.  *    the given offset is at the beginning of a line start.
  763.  */
  764.  
  765. extern short TEIsFrontOfLine(short offset, TEHandle theTE)
  766.  
  767. {    short        line = 0;
  768.  
  769.     if ((**theTE).teLength == 0)
  770.         return(true);
  771.  
  772.     if (offset >= (**theTE).teLength)
  773.         return( (*((char **)(**theTE).hText))[(**theTE).teLength - 1] == 0x0d );
  774.  
  775.     while ((**theTE).lineStarts[line] < offset)
  776.         line++;
  777.  
  778.     return( (**theTE).lineStarts[line] == offset );
  779. }
  780.  
  781. //-------------------------------------------------------------------------
  782. // TEGetLine
  783. //-------------------------------------------------------------------------
  784. /*
  785.  *    TEGetLine, given an offset and a TextEdit handle, returns the line number
  786.  *    of the line that contains the offset.
  787.  */
  788.  
  789. extern short TEGetLine(short offset, TEHandle theTE)
  790.  
  791. {    short line = 0;
  792.  
  793.     if (offset >= (**theTE).teLength)
  794.         line = (**theTE).nLines-1;
  795.     else
  796.         while ((**theTE).lineStarts[line+1] <= offset)
  797.             line++;
  798.  
  799.     return(line);
  800. }
  801.  
  802. //-------------------------------------------------------------------------
  803. // TENextLineOffset
  804. //-------------------------------------------------------------------------
  805. /*
  806.  *    TENextLineOffset, given a line and a TextEdit handle, returns the first
  807.  *    offset of the next line.
  808.  */
  809.  
  810. short TENextLineOffset(short line, TEHandle theTE)
  811.  
  812. {    short offset;
  813.  
  814.     if ( line >= (**theTE).nLines )
  815.         offset = (**theTE).teLength;
  816.     else
  817.         offset = (**theTE).lineStarts[line+1];
  818.     
  819.     return offset;
  820. }
  821.  
  822. //-------------------------------------------------------------------------
  823. // AdjustDocumentView
  824. //-------------------------------------------------------------------------
  825. /*
  826.  *    AdjustDocumentView scrolls the document image by the appropriate amount
  827.  *    if the scroll bar value has changed.
  828.  */
  829.  
  830. extern void AdjustDocumentView(Document *theDocument)
  831. {    
  832.     short delta, docTop, docTopLimit;
  833.  
  834.     delta = (theDocument->vScrollPos - GetControlValue(theDocument->vScroll)) * ScrollResolution;
  835.  
  836.     if (delta) {
  837.         if (delta > 0) {
  838.             docTop = (**(theDocument->theTE)).destRect.top;
  839.             docTopLimit = (**(theDocument->theTE)).viewRect.top + TopMargin;
  840.             if (docTop + delta > docTopLimit) {
  841.                 delta = docTopLimit - docTop;
  842.             }
  843.         }
  844.         TEScroll(0, delta, theDocument->theTE);
  845.         theDocument->vScrollPos = GetControlValue(theDocument->vScroll);
  846.     }
  847. }
  848.  
  849. //-------------------------------------------------------------------------
  850. // ScrollProc
  851. //-------------------------------------------------------------------------
  852. /*
  853.  *    ScrollProc is the function used in a call to TrackControl for
  854.  *    scrolling a document window.
  855.  */
  856.  
  857. extern pascal void ScrollProc(ControlHandle theControl, short theCode)
  858. {
  859.     short        delta = 0, pageDelta;
  860.     Document    *theDocument;
  861.     Rect        viewRect;
  862.  
  863.     if (theCode == 0)
  864.         return;
  865.  
  866.     theDocument = (Document *) (**theControl).contrlRfCon;
  867.     viewRect = (**(theDocument->theTE)).viewRect;
  868.     pageDelta = ((viewRect.bottom - viewRect.top) / ScrollResolution) - 1;
  869.  
  870.     switch(theCode) {
  871.         case kControlUpButtonPart:
  872.             delta = -1;
  873.             break;
  874.         case kControlDownButtonPart:
  875.             delta = 1;
  876.             break;
  877.         case kControlPageUpPart:
  878.             delta = -pageDelta;
  879.             break;
  880.         case kControlPageDownPart:
  881.             delta = pageDelta;
  882.             break;
  883.     }
  884.  
  885.     SetControlValue(theControl, GetControlValue(theControl) + delta);
  886.     AdjustDocumentView((Document *) (**theControl).contrlRfCon);
  887. }
  888.  
  889. //-------------------------------------------------------------------------
  890. // SUExistsThenFocus
  891. //-------------------------------------------------------------------------
  892. ODBoolean SUExistsThenFocus(Environment* ev, ODStorageUnit* su, ODPropertyName prop, ODValueType type)
  893. {
  894.     return ODSUExistsThenFocus(ev, su, prop, type);
  895. }
  896.  
  897. //-------------------------------------------------------------------------
  898. // SUForceFocus
  899. //-------------------------------------------------------------------------
  900. void SUForceFocus(Environment* ev, ODStorageUnit* su, ODPropertyName prop, ODValueType type)
  901. {
  902.     ODSUForceFocus(ev, su, prop, type);
  903. }
  904.  
  905. //-------------------------------------------------------------------------
  906. // SUSetValue
  907. //-------------------------------------------------------------------------
  908. void SUSetValue(Environment* ev, ODStorageUnit* su, ODValue value, ODULong size)
  909. {
  910.     ODULong    oldSize = su->GetSize(ev);
  911.     StorageUnitSetValue(su, ev, size, value);
  912.     if (oldSize > size)
  913.         su->DeleteValue(ev, oldSize - size);
  914. }
  915.  
  916. //-------------------------------------------------------------------------
  917. // SUFocusAndSetValue
  918. //-------------------------------------------------------------------------
  919. void SUFocusAndSetValue(Environment* ev, 
  920.                 ODStorageUnit* su, 
  921.                 ODPropertyName prop, 
  922.                 ODValueType type, 
  923.                 ODValue value, 
  924.                 ODULong size)
  925. {
  926.     SUForceFocus(ev, su, prop, type);
  927.     SUSetValue(ev, su, value, size);
  928. }
  929.  
  930. //-------------------------------------------------------------------------
  931. // SURemoveProperty
  932. //-------------------------------------------------------------------------
  933. void SURemoveProperty(Environment* ev, ODStorageUnit* su, ODPropertyName prop)
  934. {
  935.     if ( su->Exists(ev, prop, kODNULL, 0) )
  936.     {
  937.         su->Focus(ev, prop, kODPosUndefined, kODNULL, (ODValueIndex)0, kODPosUndefined);
  938.         su->Remove(ev);
  939.     }
  940. }
  941.  
  942. //-------------------------------------------------------------------------
  943. // SURemoveValue
  944. //-------------------------------------------------------------------------
  945. void SURemoveValue(Environment* ev, ODStorageUnit* su, ODPropertyName prop, ODValueType type)
  946. {
  947.     if ( su->Exists(ev, prop, type, 0) )
  948.     {
  949.         su->Focus(ev, prop, kODPosUndefined, type, (ODValueIndex)0, kODPosUndefined);
  950.         su->Remove(ev);
  951.     }
  952. }
  953.  
  954. //-------------------------------------------------------------------------
  955. // LineHeightAtOffset
  956. //-------------------------------------------------------------------------
  957. ODSShort LineHeightAtOffset(ODSShort offset, TEHandle theTEHandle)
  958. {
  959.     ODSShort height;
  960.  
  961.     // $$$$$ It seems that (*theTEHandle)->lineHeight is greater than zero
  962.     // even if the line height table exists, so just assume the lineHeigthTable
  963.     // exists.
  964.  
  965.     //if ( (*theTEHandle)->lineHeight > 0 )
  966.     //{
  967.     //    height = (*theTEHandle)->lineHeight;         /* top o' the line to you! */
  968.     //}
  969.     //else
  970.     {
  971.         ODSShort line = TEGetLine (offset, theTEHandle);
  972.         height = TEGetHeight(line, line, theTEHandle);
  973.     }
  974.     
  975.     return height;
  976. }
  977.  
  978. //-------------------------------------------------------------------------
  979. // LineBorderFromRange
  980. //-------------------------------------------------------------------------
  981. RgnHandle LineBorderFromRange(ODSShort* startOffset, ODSShort endOffset, TEHandle theTEHandle)
  982. {
  983.     if (*startOffset >= endOffset)
  984.         return kODNULL;
  985.  
  986.     Point startPoint;
  987.     Point endPoint;
  988.  
  989.     RgnHandle borderRgn = ODNewRgn();
  990.     OpenRgn();
  991.  
  992.     ODSShort startLine = TEGetLine (*startOffset, theTEHandle);
  993.     ODSShort endLine = TEGetLine (endOffset, theTEHandle);
  994.  
  995. #ifdef DEBUG_LINK_BORDERS
  996.     somPrintf("DragText: LineBorderFromRange: start line(offset) = %d(%d), end line(offset) = %d(%d)\n",
  997.                 startLine, *startOffset, endLine, endOffset);
  998. #endif
  999.  
  1000.     startPoint = TEGetPoint((short)*startOffset, theTEHandle);
  1001.  
  1002.     if ( (endLine == startLine) )
  1003.     {
  1004.         endPoint = TEGetPoint((short)endOffset, theTEHandle);
  1005.     }
  1006.     else
  1007.     {
  1008.         endPoint.h = (*theTEHandle)->viewRect.right;
  1009.         endPoint.v = startPoint.v;
  1010.     }
  1011.  
  1012.     endPoint.v -= LineHeightAtOffset(*startOffset, theTEHandle);
  1013.  
  1014. #ifdef DEBUG_LINK_BORDERS
  1015.     somPrintf("DragText: LineBorderFromRange: Line border start(h, v) = (%d, %d), end(h, v) = (%d, %d)\n", 
  1016.             startPoint.h, startPoint.v, endPoint.h, endPoint.v);
  1017. #endif
  1018.  
  1019.     MoveTo(startPoint.h, startPoint.v);
  1020.     LineTo(endPoint.h, startPoint.v);
  1021.     LineTo(endPoint.h, endPoint.v);
  1022.     LineTo(startPoint.h, endPoint.v);
  1023.     LineTo(startPoint.h, startPoint.v);
  1024.     
  1025.     CloseRgn(borderRgn);
  1026.     
  1027.     *startOffset = TENextLineOffset(startLine, theTEHandle);
  1028.  
  1029.     return borderRgn;
  1030. }
  1031.  
  1032. //-------------------------------------------------------------------------
  1033. // DrawLinkBorder
  1034. //-------------------------------------------------------------------------
  1035. //
  1036. // Based on C.K. Haun's BorderTextSection
  1037. /* this borders the selected section.  It's a pain.  */
  1038. /* BUT, it's a pain because I'm using TextEdit.  If you're writing a word processor */
  1039. /* or another application which does it's own text processing, this will be a lot easier */
  1040. /* •••• NOTE:  this doesn't look very good when a subscriber is embedded in a publisher, since */
  1041. /* the lines of course overlap.  I don't know how to deal with this yet. */
  1042. extern void DrawLinkBorder(Environment *ev,
  1043.                             ODFacet* facet,
  1044.                             ODSShort linkStart,
  1045.                             ODSShort linkEnd, 
  1046.                             TEHandle theTEHandle,
  1047.                             LinkBorderStyle borderStyle)
  1048. {
  1049.     RgnHandle borderRgn = ODNewRgn();
  1050.  
  1051.     ODPoint xForm;
  1052.     ODShape* clipShape = kODNULL;
  1053.     ODShape* frameShape = kODNULL;
  1054.     RgnHandle clipRgn, saveClip, frameRgn;
  1055.     Rect bounds;
  1056.     GrafPtr    savedQDPort;
  1057.    
  1058.        // $$$$$ KLUDGE: When linked content is moved, its possible for linkStart to be beyond the
  1059.        // current length of the text.  In that case just return.
  1060.        
  1061.        if ( linkStart >= (**theTEHandle).teLength )
  1062.            return;
  1063.        
  1064.        if ( linkEnd > (**theTEHandle).teLength )
  1065.            linkEnd = (**theTEHandle).teLength;
  1066.  
  1067.     // Link Border patterns
  1068.     Pattern unselectedLinkBorder = {0xCC, 0x99, 0x33, 0x66, 0xCC, 0x99, 0x33, 0x66};
  1069.     //Pattern oldUnselectedLinkBorder = {0x33, 0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33, 0xCC};
  1070.     //Pattern davesLinkBorder = {0x88, 0x55, 0x22, 0x55, 0x88, 0x55, 0x22, 0x55};
  1071.     Pattern selectedLinkBorder = {0x77, 0xEE, 0xDD, 0xBB, 0x77, 0xEE, 0xDD, 0xBB};
  1072.     //Pattern oldSelectedLinkBorder = {0x77, 0xEE, 0x77, 0xEE, 0x77, 0xEE, 0x77, 0xEE};
  1073.     
  1074.     ODSShort offsetStart = linkStart;
  1075.     do
  1076.     {
  1077.         RgnHandle lineRgn = LineBorderFromRange(&offsetStart, linkEnd, theTEHandle);
  1078.         if ( lineRgn != kODNULL )
  1079.         {
  1080.             UnionRgn(lineRgn, borderRgn, borderRgn);
  1081.             DisposeRgn(lineRgn);
  1082.         }
  1083. #ifdef DEBUG_LINK_BORDERS
  1084.         somPrintf("DragText: DrawLinkBorder: Loop: start offset = %d, end offset = %d\n",
  1085.             offsetStart, linkEnd);
  1086. #endif
  1087.     }
  1088.     while (offsetStart < linkEnd);
  1089.  
  1090. #ifdef DEBUG_LINK_BORDERS
  1091.     somPrintf("DragText: DrawLinkBorder: Loop done!\n");
  1092. #endif
  1093.  
  1094.     // Prepare to draw
  1095.     GetPort(&savedQDPort);
  1096.     SetPort(facet->GetCanvas(ev)->GetQDPort(ev));
  1097.     SetOrigin(0,0);
  1098.     xForm = GetAggregateTranslation(ev, facet);
  1099.     frameShape = facet->GetFrame(ev)->AcquireFrameShape(ev, kODNULL);
  1100.     frameRgn = frameShape->GetQDRegion(ev);
  1101.     clipShape = facet->AcquireClipShape(ev, kODNULL);
  1102.     clipRgn = clipShape->CopyQDRegion(ev);
  1103.     saveClip = ODNewRgn();
  1104.     
  1105.     GetClip(saveClip);
  1106.     bounds = (**frameRgn).rgnBBox;
  1107.     OffsetRect(&bounds, xForm.IntX(), xForm.IntY());
  1108.     OffsetRgn(clipRgn, xForm.IntX(), xForm.IntY());
  1109.     InsetRgn(clipRgn, 2, 2);
  1110.     SetClip(clipRgn);
  1111.  
  1112.     // Frame with four pixels of white
  1113.     PenSize(4, 4);
  1114.     PenPat(&ODQDGlobals.white);
  1115.     FrameRgn(borderRgn);
  1116.  
  1117.     if ( borderStyle == kLinkBorderOff )
  1118.     {
  1119.         Rect borderRect = (*borderRgn)->rgnBBox;
  1120.         TEUpdate(&borderRect, theTEHandle);
  1121.     }
  1122.     else
  1123.     {
  1124.         // Paint the border
  1125.         PenSize(2, 2);
  1126.         if ( borderStyle == kLinkBorderOn )
  1127.             PenPat(&unselectedLinkBorder);
  1128.         else
  1129.             PenPat(&selectedLinkBorder);
  1130.         InsetRgn(borderRgn, 1, 1);
  1131.         FrameRgn(borderRgn);
  1132.     }
  1133.  
  1134.     // Restore drawing environment
  1135.     SetPort(savedQDPort);    
  1136.     SetClip(saveClip);
  1137.     
  1138.     if (frameShape) frameShape->Release(ev);
  1139.     if (clipShape) clipShape->Release(ev);
  1140.     DisposeRgn(saveClip);
  1141.     DisposeRgn(clipRgn);
  1142.     
  1143.     PenNormal();
  1144.  
  1145.     DisposeRgn(borderRgn);
  1146. }
  1147.  
  1148. //-------------------------------------------------------------------------
  1149. // DragTextDialogFilter
  1150. //-------------------------------------------------------------------------
  1151.  
  1152. pascal Boolean DragTextDialogFilter(DialogPtr dialog,
  1153.                               EventRecord* event,
  1154.                               short* itemHit)
  1155. {
  1156.     ODBoolean handled = kODFalse;
  1157.     
  1158.     Environment* ev = somGetGlobalEnvironment();
  1159.     
  1160.     ODSession* session = (ODSession*) ((WindowPeek)dialog)->refCon;
  1161.     
  1162.     if (event->what == nullEvent)
  1163.     {
  1164.         session->GetDispatcher(ev)->Dispatch(ev, (ODEventData*)event);
  1165.     }
  1166.     else if (event->what == updateEvt &&
  1167.                 (WindowPtr) event->message != dialog)        
  1168.     {
  1169.         session->GetDispatcher(ev)->Dispatch(ev, (ODEventData*)event);
  1170.     }
  1171.     else if (event->what == activateEvt &&
  1172.                 (WindowPtr) event->message != dialog)        
  1173.     {
  1174.         session->GetDispatcher(ev)->Dispatch(ev, (ODEventData*)event);
  1175.     }
  1176.     else if (event->what == mouseDown)
  1177.     {
  1178.         handled = kODFalse;
  1179.     }
  1180.     else if (event->what == mouseUp)
  1181.     {
  1182.         handled = kODTrue;
  1183.     }
  1184.     else if ((event->what == keyDown) || (event->what == autoKey))
  1185.     {
  1186.         handled = kODTrue;
  1187.     }
  1188.  
  1189.     return handled;
  1190. }
  1191.  
  1192. //-------------------------------------------------------------------------
  1193. // GetFSSpecFromHFSProperty
  1194. //-------------------------------------------------------------------------
  1195.  
  1196. ODBoolean GetFSSpecFromHFSProperty(Environment* ev,
  1197.             ODStorageUnit* su,
  1198.             FSSpec* fileSpec)
  1199. {
  1200.     ODBoolean result = kODFalse;
  1201.  
  1202.     if ( ODSUExistsThenFocus(ev, su, kODPropContents, kODApplehfs) )
  1203.     {
  1204.         ODULong hfsflavorSize = su->GetSize(ev);
  1205.         HFSFlavor* hfsflavorData = (HFSFlavor*) ODNewPtr(hfsflavorSize, kDefaultHeapID);
  1206.         StorageUnitGetValue(su, ev, hfsflavorSize, (ODValue) hfsflavorData);
  1207.         
  1208.         *fileSpec = hfsflavorData->fileSpec;
  1209.         
  1210.         ODDisposePtr((ODPtr) hfsflavorData);
  1211.         result = kODTrue;
  1212.     }
  1213.  
  1214.     return result;
  1215. }
  1216.  
  1217. //-------------------------------------------------------------------------
  1218. // ReadTextFile
  1219. //-------------------------------------------------------------------------
  1220.  
  1221. ODHandle ReadTextFile(FSSpec* fileSpec, ODBoolean* truncated)
  1222. {
  1223.     Size                textSize;
  1224.     OSErr                error = noErr;
  1225.     short                fileRefNum = 0;
  1226.     ODHandle            textHandle = kODNULL;
  1227.     Size                bytesRead;
  1228.     
  1229.     *truncated = kODFalse;
  1230.  
  1231.     THROW_IF_ERROR(FSpOpenDF(fileSpec, fsRdPerm, &fileRefNum));
  1232.     TRY
  1233.         THROW_IF_ERROR(GetEOF(fileRefNum,&textSize));
  1234.     
  1235.         if ( textSize > kMaxTextSize )
  1236.         {
  1237.             *truncated = kODTrue;
  1238.             textSize = kMaxTextSize;
  1239.         }
  1240.  
  1241.         textHandle = ODNewHandle(textSize);
  1242.  
  1243.         if (textSize > 0)
  1244.         {
  1245.             THROW_IF_ERROR(SetFPos(fileRefNum,fsFromStart,0));
  1246.     
  1247.             bytesRead = textSize;
  1248.             ODLockHandle(textHandle);
  1249.             error = FSRead(fileRefNum, &bytesRead, *textHandle);
  1250.             ODUnlockHandle(textHandle);
  1251.             PRINT("DragText: ReadTextFile: Read %d bytes\n", bytesRead);
  1252.                 
  1253.             if ( (error != noErr) && (error != eofErr) )
  1254.                 THROW(error);
  1255.         }
  1256.  
  1257.         FSClose(fileRefNum);
  1258.     CATCH_ALL
  1259.         FSClose(fileRefNum);
  1260.         ODDisposeHandle(textHandle);
  1261.         RERAISE;
  1262.     ENDTRY
  1263.  
  1264.     return textHandle;
  1265. }
  1266.  
  1267. //-------------------------------------------------------------------------
  1268. // InsertFromTextFile
  1269. //-------------------------------------------------------------------------
  1270.  
  1271. void InsertFromTextFile(FSSpec* fileSpec, TEHandle theTE, ODULong insertPosition)
  1272. {
  1273.     Size                textSize;
  1274.     OSErr                error = noErr;
  1275.     short                fileRefNum = 0;
  1276.     ODPtr                textBuffer = kODNULL;
  1277.     Size                bytesRead;
  1278.     Size                totalBytesRead = 0;
  1279.     
  1280.     const ODULong    kBufferSize = 2000;
  1281.  
  1282.     THROW_IF_ERROR(FSpOpenDF(fileSpec, fsRdPerm, &fileRefNum));
  1283.     TRY
  1284.         THROW_IF_ERROR(GetEOF(fileRefNum,&textSize));
  1285.     
  1286.         if (textSize == 0)
  1287.         {
  1288.             FSClose(fileRefNum);
  1289.             return;
  1290.         }
  1291.         
  1292.         if ( textSize + ((**theTE).teLength) > kMaxTextSize )
  1293.             THROW(kDragTextErrTooMuchText);
  1294.  
  1295.         THROW_IF_ERROR(SetFPos(fileRefNum,fsFromStart,0));
  1296.  
  1297.         textBuffer = ODNewPtr(kBufferSize);
  1298.  
  1299.         TESetSelect(insertPosition, insertPosition, theTE);
  1300.  
  1301.         bytesRead = kBufferSize;
  1302.         while ( error != noErr )
  1303.         {
  1304.             bytesRead = kBufferSize;
  1305.             error = FSRead(fileRefNum, &bytesRead, textBuffer);
  1306.             PRINT("DragText: InsertFromTextFile: Read %d bytes\n", bytesRead);
  1307.  
  1308.             TEInsert(textBuffer, bytesRead, theTE);
  1309.             PRINT("DragText: InsertFromTextFile: Text inserted\n");
  1310.             
  1311.             totalBytesRead += bytesRead;
  1312.         }
  1313.         PRINT("DragText: InsertFromTextFile: %d bytes inserted from file\n", totalBytesRead);
  1314.             
  1315.         ODDisposePtr(textBuffer);
  1316.         
  1317.         if ( error != eofErr )
  1318.             THROW(error);
  1319.         
  1320.         // The newly inserted text should begin on a new line
  1321.         if ( (insertPosition > 0) && (GetCharAtOffset(insertPosition, theTE) != 0x0D) )
  1322.         {
  1323.             PRINT("DragText: InsertFromTextFile: Inserting newline before text\n");
  1324.             TESetSelect(insertPosition, insertPosition, theTE);
  1325.             TEKey((char) 0x0D, theTE);
  1326.         }
  1327.  
  1328.         // Unless the file ended with an empty line, insert a new line at the end
  1329.         ODULong insertEnd = insertPosition + totalBytesRead;
  1330.         if ( (insertEnd < (**theTE).teLength) && (GetCharAtOffset(insertEnd, theTE) != 0x0D) )
  1331.         {
  1332.             PRINT("DragText: InsertFromTextFile: Inserting newline after text\n");
  1333.             TESetSelect(insertEnd+1, insertEnd+1, theTE);
  1334.             TEKey((char) 0x0D, theTE);
  1335.         }
  1336.  
  1337.         FSClose(fileRefNum);
  1338.     CATCH_ALL
  1339.         FSClose(fileRefNum);
  1340.         RERAISE;
  1341.     ENDTRY
  1342. }
  1343.  
  1344. //-------------------------------------------------------------------------
  1345. // IsFrontProcess
  1346. //-------------------------------------------------------------------------
  1347.  
  1348. ODBoolean IsFrontProcess()
  1349. {
  1350.     ProcessSerialNumber myProcess, frontProcess;
  1351.     ODBoolean inFront = kODFalse;
  1352.  
  1353.     GetCurrentProcess(&myProcess);
  1354.     GetFrontProcess(&frontProcess);
  1355.     SameProcess(&myProcess, &frontProcess, &inFront);
  1356.  
  1357.     return inFront;
  1358. }
  1359.